'use strict';

const gulp = require('gulp'),
    watchify = require('watchify'),
    rename = require('gulp-rename'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    stylus = require('gulp-stylus'),
    gutil = require('gulp-util'),
    notifier = require('node-notifier'),
    inject = require('gulp-inject'),
    del = require('del'),
    conf = require('./gulpconf');

/*****************************************************************
 * configuration
 *****************************************************************/
let hash = Date.now();
const P = conf.PATH;
const CORE = conf.core;
const TASKS = conf.tasks;

/*****************************************************************
 * functions
 *****************************************************************/
/**
 * inject to html
 */
function injectHTML(targetHTML, injectName, mode) {
    injectName = injectName.replace(/\//g, '_');
    const targetObject = gulp.src(`./${P.VIEWS}/${targetHTML}.html`);
    let sourcesCss = gulp.src(`${P.DIST_STYLES}/bundle/${injectName}.css`, {read: false});
    let sourcesJs = gulp.src(`${P.DIST_SCRIPTS}/bundle/${injectName}.js`, {read: false});

    if(mode === 'build') {
        sourcesCss = gulp.src(`${P.DIST_STYLES}/build/${injectName}.min.${hash}.css`, {read: false});
        sourcesJs = gulp.src(`${P.DIST_SCRIPTS}/build/${injectName}.min.${hash}.js`, {read: false});
    }

    // fix sub folder bug
    let dest = `./${P.VIEWS}`;
    const index = targetHTML.lastIndexOf('/');
    if(index !== -1) {
        dest += '/' + targetHTML.substring(0, index);
    }

    // inject
    targetObject.pipe(inject(sourcesCss, {
            addRootSlash: false,
            transform :(filePath) => {
                return `<link rel="stylesheet" href="${filePath.substring(P.PUBLIC.length)}"/>`;
            }
        }))
        .pipe(gulp.dest(dest))
        .pipe(inject(sourcesJs, {
            addRootSlash: false,
            transform :(filePath) => {
                return `<script src="${filePath.substring(P.PUBLIC.length)}"></script>`;
            }
        }))
        .pipe(gulp.dest(dest));
}

/**
 * generate style
 */
function generateStyle(src, target, mode) {
    target = target.replace(/\//g, '_');
    if(src) {
        if(mode === 'build') {
            return gulp.src(src)
                .pipe(stylus({ compress: true }))
                .pipe(rename(`${target}.min.${hash}.css`))
                .pipe(gulp.dest(`${P.DIST_STYLES}/build`));
        } else {
            return gulp.src(src)
                .pipe(stylus())
                .pipe(rename(`${target}.css`))
                .pipe(gulp.dest(`${P.DIST_STYLES}/bundle`));
        }
    }
}

/**
 * generate script
 */
function generateScript(src, target, mode) {
    target = target.replace(/\//g, '_');
    if(src) {
        if(mode === 'build') {
            return gulp.src(src)
                .pipe(concat(`${target}.js`))
                .pipe(gulp.dest(`${P.DIST_SCRIPTS}/bundle`))
                .pipe(rename({ suffix: '.min.' + hash }))
                .pipe(uglify().on('error', gutil.log))
                .pipe(gulp.dest(`${P.DIST_SCRIPTS}/build`));
        } else {
            return gulp.src(src)
                .pipe(concat(`${target}.js`))
                .pipe(gulp.dest(`${P.DIST_SCRIPTS}/bundle`));
        }
    }
}

/*****************************************************************
 * core tasks
 *****************************************************************/

/******************** dev core ******************/

/** dev core css **/
gulp.task('core-style-dev', () => {
    return generateStyle(CORE.style, `${P.APP}`, `dev`);
});

/** dev core js **/
gulp.task('core-script-dev', () => {
    return generateScript(CORE.script, `${P.APP}`, `dev`);
});

/** !!!! dev core !!!! **/
gulp.task('core-dev', ['core-style-dev', 'core-script-dev'], () => {
    // // inject html
    injectHTML(`${P.BASE_VIEW}`, `${P.APP}`, `dev`);
    injectHTML(`${P.BASE_VIEW}1`, `${P.APP}`, `dev`);
    
    setTimeout(() => {
        // watch style
        gulp.watch(`${P.STYLES}/**/*.styl`, [`core-style-dev`]);
        // watch script
        CORE.script.forEach((script) => {
            gulp.watch(script, [`core-script-dev`]);
        });
    }, 50);
});

/******************** build core ******************/

/** build core clean **/
gulp.task('core-clean-build', () => {
    del([`${P.DIST_STYLES}/build/${P.APP}.min.*.css`]);
    del([`${P.DIST_SCRIPTS}/build/${P.APP}.min.*.js`]);
});

/** build core css **/
gulp.task('core-style-build', () => {
    return generateStyle(CORE.style, `${P.APP}`, `build`);
});

/** build core js **/
gulp.task('core-script-build', () => {
    return generateScript(CORE.script, `${P.APP}`, `build`);
});

/** !!!! build core !!!! **/
gulp.task('core-build', ['core-clean-build', 'core-style-build', 'core-script-build'], () => {
    injectHTML(`${P.BASE_VIEW}`, `${P.APP}`, `build`);
    injectHTML(`${P.BASE_VIEW}1`, `${P.APP}`, `build`);
});

/*******************************************************************
 * app tasks
 ******************************************************************/
const devTasks = [];
const buildTasks = [];

for(const target in TASKS) {
    global.target = target;
    global.hash = hash;

    if(TASKS.hasOwnProperty(target)) {
        const task = TASKS[target];
        const devTask = `${target}-dev`;
        const buildTask = `${target}-build`;
        const devStyleTask = `${target}-style-dev`;
        const devScriptTask = `${target}-script-dev`;
        const buildStyleTask = `${target}-style-build`;
        const buildScriptTask = `${target}-script-build`;

        /************************** dev page *******************************/
        /** dev target style **/
        gulp.task(devStyleTask, () => {
            return generateStyle(task.style, target, `dev`);
        });

        /** dev target script **/
        gulp.task(devScriptTask, () => {
            return generateScript(task.script, target, `dev`);
        });

        /** !!!! dev target !!!! **/
        gulp.task(devTask, [devStyleTask, devScriptTask], () => {
            // inject html
            injectHTML(target, target, `dev`);

            setTimeout(() => {
                // watch style
                if(task.style) {
                    gulp.watch(task.style, [devStyleTask]);
                }
                // watch script
                if(task.script) {
                    task.script.forEach((script) => {
                        gulp.watch(script, [devScriptTask]);
                    });
                }
            }, 50);
        });

        /************************** build page *******************************/
        /** build target clean **/
        const buildCleanTarget = `${target}-clean-build`;
        gulp.task(buildCleanTarget, () => {
            del([`${P.DIST_STYLES}/build/${target}.min.*.css`]);
            del([`${P.DIST_SCRIPTS}/build/${target}.min.*.js`]);
        });

        /** build target style **/
        gulp.task(buildStyleTask, () => {
            return generateStyle(task.style, target, `build`);
        });

        /** build target script **/
        gulp.task(buildScriptTask, () => {
            return generateScript(task.script, target, `build`);
        });

        /** !!!! build target !!!! **/
        gulp.task(buildTask, [buildCleanTarget, buildStyleTask, buildScriptTask], () => {
            injectHTML(target, target, `build`);
        });

        // push to array
        devTasks.push(devTask);
        buildTasks.push(buildTask);
    }
}

/*************************** developement ***************************/
gulp.task('dev', ['core-dev'].concat(devTasks), () => {
    notifier.notify({ message: `Dev is ready` });
});

/*************************** production ***************************/
gulp.task('build', ['core-build'].concat(buildTasks), function() {
    notifier.notify({ message: `Build completed` });
});